/*
 * 代号：凤凰
 * http://www.jphenix.org
 * 2014-06-13
 * V4.0
 */
package com.jphenix.webserver.api;

import com.jphenix.standard.docs.ClassInfo;
import com.jphenix.standard.servlet.api.ServletInputStream;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * 服务输入流类
 * 
 * 2019-09-17 整理了代码格式
 * 2019-09-20 去掉了调试打印堆栈信息
 * 2021-03-17 适配tomcat9中的 servlet-api.jar
 * 2022-09-04 重构了内置Servlet容器，不依赖外部ServletApi包
 * 
 * @author 刘虻
 * 2006-9-15上午12:19:07
 */
@ClassInfo({"2022-09-04 21:58","ServeInputStream"})
public class ServletInputStreamImpl extends ServletInputStream {
	
	private final static boolean STREAM_DEBUG = false;

	private BufferedInputStream in;
	private int                 chunksize         = 0;
	private boolean             chunking          = false;
	private boolean             returnedAsReader;
	private boolean             returnedAsStream;
	private long                contentLength     = -1;
	private long                readCount;

	/**
	 * 构造函数
	 * 2008-7-9上午02:46:02
	 */
	public ServletInputStreamImpl(InputStream in) {
		super(in);
		this.in = new BufferedInputStream(in);
	}

	/**
	 * 重置
	 * 2019年9月17日
	 * @author MBG
	 */
	public void refresh() {
		returnedAsReader = false;
		returnedAsStream = false;
		contentLength    = -1;
		readCount        = 0;
		chunksize        = 0;
	}

	/**
	 * 母鸡
	 * @author 刘虻
	 * 2008-7-9上午03:22:27
	 * @param chunking 母鸡
	 */
	public void chunking(boolean chunking) {
		if (contentLength == -1) {
			this.chunking = chunking;
		}
	}


	/**
	 * 母鸡
	 * @author 刘虻
	 * 2008-7-9上午03:22:38
	 * @param contentLength 母鸡
	 */
	public void setContentLength(long contentLength) {
		if (this.contentLength == -1 && contentLength >= 0 && chunking == false) {
			this.contentLength = contentLength;
			readCount = 0;
		}
	}


	/**
	 * 母鸡
	 * @author 刘虻
	 * 2008-7-9上午03:22:49
	 * @return 母鸡
	 * @throws IOException 执行发生异常
	 */
	public String readLine() throws IOException {
		StringBuffer buf = new StringBuffer(1024);

		int c;
		boolean cr = false;
		LineLoop: while ((c = chunking || contentLength >= 0 ? read() : in.read()) != -1) {
			switch (c) {
			case 10:
				break LineLoop;

			case 13:
				cr = true;
				if (!chunking) {
					in.mark(2);
				}
				break;

			default:
				if (cr) {
					in.reset();
					break LineLoop;
				} else {
					buf.append((char) c);
				}
				break;
			}
		}

		if (c == -1 && buf.length() == 0) {
			return null;
		}
		if (STREAM_DEBUG) {
			System.err.println(buf.toString());
		}

		return buf.toString();
	}

	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-7-9上午03:23:01
	 */
	@Override
    public int read() throws IOException {
		if (chunking) {
			int b = -1;
			if (chunksize <= 0 && getChunkSize() <= 0) {
				return -1;
			}
			b = in.read();
			chunksize = (b < 0) ? -1 : (chunksize - 1);
			if (STREAM_DEBUG) {
				if (b >= 0) {
					System.err.print((char) b);
				} else {
					System.err.print("EOF");
				}
			}
			return b;
		}

		if (contentLength >= 0) {
			if (readCount >= contentLength) {
				if (STREAM_DEBUG) {
					System.err.print("EOF");
				}
				return -1;
			}
			readCount++;
		}

		if(STREAM_DEBUG) {
			int c = in.read();
			if (c >= 0) {
				System.err.print((char) c);
			}
			return c;
		}
		return in.read();
	}

	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-7-9上午03:23:07
	 */
	@Override
    public int read(byte[] b) throws IOException {
		return read(b, 0, b.length);
	}

	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-7-9上午03:23:11
	 */
	@Override
    public int read(byte[] b, int off, int len) throws IOException {
		if (chunking) {
			if (chunksize <= 0 && getChunkSize() <= 0) {
				return -1;
			}
			if (len > chunksize) {
				len = chunksize;
			}
			len = in.read(b, off, len);
			chunksize = (len < 0) ? -1 : (chunksize - len);
		} else {
			if (contentLength >= 0) {
				if (contentLength - readCount < Integer.MAX_VALUE) {
					len = Math.min(len, (int) (contentLength - readCount));
				}
				if (len <= 0) {
					if (STREAM_DEBUG) {
						System.err.print("EOF");
					}
					return -1;
				}
				len = in.read(b, off, len);
				readCount += len;
			} else {
				len = in.read(b, off, len);
			}
		}
		if (STREAM_DEBUG) {
			System.err.print(new String(b, off, len));
		}
		return len;
	}

	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-7-9上午03:23:17
	 */
	@Override
    public long skip(long len) throws IOException {
		if (chunking) {
			if (chunksize <= 0 && getChunkSize() <= 0) {
				return -1;
			}
			if (len > chunksize) {
				len = chunksize;
			}
			len = in.skip(len);
			chunksize = (len < 0) ? -1 : (chunksize - (int) len);
		} else {
			if (contentLength >= 0) {
				len = Math.min(len, contentLength - readCount);
				if (len <= 0) {
					return -1;
				}
				len = in.skip(len);
				readCount += len;
			} else {
				len = in.skip(len);
			}
		}
		return len;
	}

	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-7-9上午03:23:22
	 */
	@Override
    public int available() throws IOException {
		if (chunking) {
			int len = in.available();
			if (len <= chunksize) {
				return len;
			}
			return chunksize;
		}

		if (contentLength >= 0) {
			int len = in.available();
			if (contentLength - readCount < Integer.MAX_VALUE) {
				return Math.min(len, (int) (contentLength - readCount));
			}
			return len;
		} else {
			return in.available();
		}
	}

	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-7-9上午03:23:27
	 */
	@Override
    public void close() throws IOException {
		if (STREAM_DEBUG) {
			System.err.println("instream.close()");
		}
		chunksize = -1;
		if (contentLength >= 0) {
			contentLength = readCount;
		}
	}

	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-7-9上午03:23:32
	 */
	@Override
    public boolean markSupported() {
		return false;
	}

	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-7-9上午03:23:36
	 */
	@Override
    public void reset() throws IOException {
		if (STREAM_DEBUG) {
			System.err.println("instream.reset()");
		}
		in.reset();
	}

	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-7-9上午03:23:41
	 */
	@Override
    public void mark(int readlimit) {
		if (STREAM_DEBUG) {
			System.err.println("instream.mark(" + readlimit + ")");
		}
	}

	/**
	 * 母鸡
	 * @author 刘虻
	 * 2008-7-9上午03:23:43
	 * @return 母鸡 
	 * @throws IOException 执行发生异常
	 */
	public int getChunkSize() throws IOException {
		if (chunksize < 0) {
			return -1;
		}

		chunksize = -1;
		chunking = false;
		String line = readLine();
		while (line != null && line.length() == 0) {
			line = readLine();
		}
		chunking = true;
		if (line == null) {
			return -1;
		}
		int i = line.indexOf(';');
		if (i > 0) {
			line = line.substring(0, i).trim();
		}
		chunksize = Integer.parseInt(line, 16);
		if (chunksize == 0) {
			chunksize = -1;
			chunking = false;
		}
		return chunksize;
	}

	/**
	 * 母鸡
	 * @author 刘虻
	 * 2008-7-9上午03:23:56
	 * @return 母鸡
	 */
	public boolean isReturnedAsStream() {
		return returnedAsStream;
	}

	/**
	 * 母鸡
	 * @author 刘虻
	 * 2008-7-9上午03:24:00
	 * @param _on 母鸡
	 */
	public void setReturnedAsStream(boolean _on) {
		returnedAsStream = _on;
	}

	/**
	 * 母鸡
	 * @author 刘虻
	 * 2008-7-9上午03:24:05
	 * @return 母鸡
	 */
	public boolean isReturnedAsReader() {
		return returnedAsReader;
	}

	/**
	 * 母鸡
	 * @author 刘虻
	 * 2008-7-9上午03:24:12
	 * @param _on 母鸡
	 */
	public void setReturnedAsReader(boolean _on) {
		returnedAsReader = _on;
	}
}